import java.net.*;
import java.io.*;
import java.util.*;

// 可以在控制台运行的客户端
public class Client {

	// 提示信息前缀
	private String notif = " *** ";

	// 用于输入/输出
	private ObjectInputStream sInput;		// 从 socket 读取数据
	private ObjectOutputStream sOutput;		// 向 socket 写入数据
	private Socket socket;					// socket 对象

	private String server, username;		// 服务器地址和用户名
	private int port;						// 端口号

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}
	Client(String server, int port, String username) {
		this.server = server;
		this.port = port;
		this.username = username;
	}

	/*
	 * 启动聊天客户端
	 */
	public boolean start() {
		// 尝试连接服务器
		try {
			socket = new Socket(server, port);
		}
		catch(Exception ec) {
			display("连接服务器失败：" + ec.getMessage());
			return false;
		}

		String msg = "成功连接至服务器：" + socket.getInetAddress() + ":" + socket.getPort();
		display(msg);

		/* 创建输入输出流对象 */
		try {
			sInput  = new ObjectInputStream(socket.getInputStream());
			sOutput = new ObjectOutputStream(socket.getOutputStream());
		}
		catch (IOException eIO) {
			display("创建输入输出流异常：" + eIO.getMessage());
			return false;
		}

		// 创建线程监听来自服务器的消息
		new ListenFromServer().start();

		// 向服务器发送用户名，这是唯一使用字符串发送的消息
		// 其他消息都将通过 ChatMessage 对象传输
		try {
			sOutput.writeObject(username);
		}
		catch (IOException eIO) {
			display("登录时发生异常：" + eIO.getMessage());
			disconnect();
			return false;
		}
		// 成功连接
		return true;
	}

	/*
	 * 显示消息到控制台
	 */
	private void display(String msg) {
		System.out.println(msg);
	}

	/*
	 * 向服务器发送消息
	 */
	void sendMessage(ChatMessage msg) {
		try {
			sOutput.writeObject(msg);
		}
		catch(IOException e) {
			display("向服务器发送消息失败：" + e.getMessage());
		}
	}

	/*
	 * 断开连接，关闭所有资源
	 */
	private void disconnect() {
		try { if(sInput != null) sInput.close(); } catch(Exception e) {}
		try { if(sOutput != null) sOutput.close(); } catch(Exception e) {}
		try{ if(socket != null) socket.close(); } catch(Exception e) {}
	}
	public static void main(String[] args) {
		// 默认值
		int portNumber = 1500;
		String serverAddress = "localhost";
		String userName = "Anonymous";
		Scanner scan = new Scanner(System.in);

		System.out.println("请输入用户名：");
		userName = scan.nextLine();

		switch(args.length) {
			case 3:
				serverAddress = args[2];
			case 2:
				try {
					portNumber = Integer.parseInt(args[1]);
				}
				catch(Exception e) {
					System.out.println("端口号格式错误，请输入合法数字。");
					System.out.println("使用方法: > java Client [用户名] [端口号] [服务器地址]");
					return;
				}
			case 1:
				userName = args[0];
			case 0:
				break;
			default:
				System.out.println("参数数量不正确，请按以下格式输入：");
				System.out.println("> java Client [用户名] [端口号] [服务器地址]");
				return;
		}

		// 创建客户端实例
		Client client = new Client(serverAddress, portNumber, userName);

		// 连接服务器
		if(!client.start()) {
			System.out.println("无法连接到服务器，程序终止。");
			return;
		}

		// 输出欢迎语与操作指南
		System.out.println("\n欢迎来到聊天室！");
		System.out.println("使用说明：");
		System.out.println("1. 直接输入内容并回车，可将消息群发给所有在线用户");
		System.out.println("2. 输入 '@用户名 内容'（不带引号）可向指定用户发送私聊消息");
		System.out.println("3. 输入 'WHOISIN'（不带引号）可查看当前在线用户列表");
		System.out.println("4. 输入 'LOGOUT'（不带引号）可安全退出聊天室");

		// 循环接收用户输入
		while(true) {
			System.out.print("> ");
			String msg = scan.nextLine();

			if(msg.equalsIgnoreCase("LOGOUT")) {
				client.sendMessage(new ChatMessage(ChatMessage.LOGOUT, ""));
				break;
			}
			else if(msg.equalsIgnoreCase("WHOISIN")) {
				client.sendMessage(new ChatMessage(ChatMessage.WHOISIN, ""));
			}
			else {
				client.sendMessage(new ChatMessage(ChatMessage.MESSAGE, msg));
			}
		}

		// 关闭资源
		scan.close();
		client.disconnect();
	}

	/*
	 * 用于监听服务器发来的消息的线程类
	 */
	class ListenFromServer extends Thread {

		public void run() {
			while(true) {
				try {
					// 从服务器读取消息
					String msg = (String) sInput.readObject();
					// 显示消息
					System.out.println(msg);
					System.out.print("> ");
				}
				catch(IOException e) {
					display(notif + "服务器已断开连接：" + e.getMessage() + notif);
					break;
				}
				catch(ClassNotFoundException e2) {
					// 忽略
				}
			}
		}
	}
}